using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using UwinEducation.Application.Common.Interfaces;
using UwinEducation.Application.Dtos;
using UwinEducation.Application.Extensions;
using UwinEducation.Domain.Entities;
using UwinEducation.Domain.IRepositories;
using UwinEducation.Infrastructure.Persistence;
using UwinEducation.Shared.Enums;
using UwinEducation.Shared.Models;

namespace UwinEducation.Application.Services
{
    /// <summary>
    /// 学生课表详情服务实现
    /// </summary>
    public class StudentScheduleDetailsService : IStudentScheduleDetailsService
    {
        private readonly IStudentScheduleDetailsRepository _studentScheduleDetailsRepository;
        private readonly IOrderDetailRepository _orderDetailRepository;
        private readonly ITeacherScheduleDetailsRepository _teacherScheduleDetailsRepository;
        private readonly ApplicationDbContext _context;
        private readonly IMapper _mapper;
        private readonly ILogger<StudentScheduleDetailsService> _logger;

        public StudentScheduleDetailsService(
            IStudentScheduleDetailsRepository studentScheduleDetailsRepository,
            IOrderDetailRepository orderDetailRepository,
            ITeacherScheduleDetailsRepository teacherScheduleDetailsRepository,
            IMapper mapper,
            ApplicationDbContext context,
            ILogger<StudentScheduleDetailsService> logger
        )
        {
            _studentScheduleDetailsRepository = studentScheduleDetailsRepository;
            _orderDetailRepository = orderDetailRepository;
            _teacherScheduleDetailsRepository = teacherScheduleDetailsRepository;
            _mapper = mapper;
            _context = context;
            _logger = logger;
        }

        /// <summary>
        /// 获取学生课表详情
        /// </summary>
        public async Task<StudentScheduleDetailsDto> GetByIdAsync(Guid id)
        {
            var detail = await _studentScheduleDetailsRepository.GetByIdAsync(id);
            if (detail == null)
            {
                throw new ArgumentException("学生课表详情不存在", nameof(id));
            }
            return _mapper.Map<StudentScheduleDetailsDto>(detail);
        }

        /// <summary>
        /// 获取订单详情下的所有课表详情
        /// </summary>
        public async Task<List<StudentScheduleDetailsDto>> GetByOrderDetailIdAsync(
            Guid orderDetailId
        )
        {
            var details = await _studentScheduleDetailsRepository.GetByOrderDetailIdAsync(
                orderDetailId
            );
            return _mapper.Map<List<StudentScheduleDetailsDto>>(details);
        }

        /// <summary>
        /// 获取教师课表详情下的所有学生课表
        /// </summary>
        public async Task<List<StudentScheduleDetailsDto>> GetByTeacherScheduleDetailsIdAsync(
            Guid teacherScheduleDetailsId
        )
        {
            var details =
                await _studentScheduleDetailsRepository.GetByTeacherScheduleDetailsIdAsync(
                    teacherScheduleDetailsId
                );
            return _mapper.Map<List<StudentScheduleDetailsDto>>(details);
        }

        /// <summary>
        /// 根据状态获取学生课表详情
        /// </summary>
        public async Task<List<StudentScheduleDetailsDto>> GetByStatusAsync(ScheduleStatus status)
        {
            var details = await _studentScheduleDetailsRepository.GetByStatusAsync(status);
            return _mapper.Map<List<StudentScheduleDetailsDto>>(details);
        }

        /// <summary>
        /// 获取指定时间范围内的学生课表详情
        /// </summary>
        public async Task<List<StudentScheduleDetailsDto>> GetByDateRangeAsync(
            Guid orderDetailId,
            DateTime startTime,
            DateTime endTime
        )
        {
            var details = await _studentScheduleDetailsRepository.GetByDateRangeAsync(
                orderDetailId,
                startTime,
                endTime
            );
            return _mapper.Map<List<StudentScheduleDetailsDto>>(details);
        }

        /// <summary>
        /// 创建学生课表详情
        /// </summary>
        public async Task<StudentScheduleDetailsDto> CreateAsync(
            CreateStudentScheduleDetailsDto createDto
        )
        {
            // 1. 验证订单详情是否存在
            var orderDetail = await _orderDetailRepository.GetByIdAsync(createDto.OrderDetailId);
            if (orderDetail == null)
            {
                throw new ArgumentException("订单详情不存在", nameof(createDto.OrderDetailId));
            }

            // 2. 验证教师课表详情是否存在
            var teacherScheduleDetail = await _teacherScheduleDetailsRepository.GetByIdAsync(
                createDto.TeacherScheduleDetailsId
            );
            if (teacherScheduleDetail == null)
            {
                throw new ArgumentException(
                    "教师课表详情不存在",
                    nameof(createDto.TeacherScheduleDetailsId)
                );
            }

            // 3. 检查时间冲突
            var hasConflict = await _studentScheduleDetailsRepository.HasTimeConflictAsync(
                createDto.OrderDetailId,
                teacherScheduleDetail.StartTime,
                teacherScheduleDetail.EndTime
            );

            if (hasConflict)
            {
                throw new ArgumentException("该时间段已有其他课程安排");
            }

            // 4. 创建学生课表详情
            var detail = StudentScheduleDetails.Create(
                createDto.OrderDetailId,
                createDto.TeacherScheduleDetailsId,
                createDto.IsForceCheck,
                createDto.CourseType,
                null,
                createDto.Remarks
            );

            // 5. 保存学生课表详情
            await _studentScheduleDetailsRepository.AddAsync(detail);

            return _mapper.Map<StudentScheduleDetailsDto>(detail);
        }

        /// <summary>
        /// 批量创建学生课表详情
        /// </summary>
        public async Task<List<StudentScheduleDetailsDto>> CreateRangeAsync(
            List<CreateStudentScheduleDetailsDto> createDtos
        )
        {
            // 1. 获取所有订单详情
            var orderDetailIds = createDtos.Select(x => x.OrderDetailId).Distinct().ToList();
            var orderDetails = await Task.WhenAll(
                orderDetailIds.Select(id => _orderDetailRepository.GetByIdAsync(id))
            );

            if (orderDetails.Any(x => x == null))
            {
                throw new ArgumentException("部分订单详情不存在");
            }

            // 2. 获取所有教师课表详情
            var teacherScheduleDetailIds = createDtos
                .Select(x => x.TeacherScheduleDetailsId)
                .Distinct()
                .ToList();
            var teacherScheduleDetails = await Task.WhenAll(
                teacherScheduleDetailIds.Select(id =>
                    _teacherScheduleDetailsRepository.GetByIdAsync(id)
                )
            );

            if (teacherScheduleDetails.Any(x => x == null))
            {
                throw new ArgumentException("部分教师课表详情不存在");
            }

            // 3. 创建学生课表详情列表
            var details = createDtos
                .Select(dto =>
                    StudentScheduleDetails.Create(
                        dto.OrderDetailId,
                        dto.TeacherScheduleDetailsId,
                        dto.IsForceCheck,
                        dto.CourseType,
                        null,
                        dto.Remarks
                    )
                )
                .ToList();

            // 4. 批量保存学生课表详情
            await _studentScheduleDetailsRepository.AddRangeAsync(details);

            return _mapper.Map<List<StudentScheduleDetailsDto>>(details);
        }

        /// <summary>
        /// 更新学生课表详情
        /// </summary>
        public async Task<StudentScheduleDetailsDto> UpdateAsync(
            UpdateStudentScheduleDetailsDto updateDto
        )
        {
            // 1. 获取学生课表详情
            var detail = await _studentScheduleDetailsRepository.GetByIdAsync(updateDto.Id);
            bool isAbandoned = false;
            if (detail == null)
            {
                throw new ArgumentException("学生课表详情不存在", nameof(updateDto.Id));
            }

            // 2. 更新学生课表详情
            if (updateDto.Status.HasValue)
            {
                detail.Status = updateDto.Status.Value;
                detail.Reason = updateDto.Reason;
                if (updateDto.Status.Value == ScheduleStatus.Abandoned)
                {
                    isAbandoned = true;
                }
            }

            if (!string.IsNullOrEmpty(updateDto.Remarks))
            {
                detail.Remarks = updateDto.Remarks;
            }
            if (updateDto.CourseType.HasValue)
            {
                detail.CourseType = updateDto.CourseType.Value;
            }

            // 3. 保存更新
            await _studentScheduleDetailsRepository.UpdateAsync(detail);

            //如果老师课程是1V1


            if (isAbandoned)
            {
                var teacherSchedule = await _context.TeacherSchedules.FirstOrDefaultAsync(x =>
                    x.Id == detail.TeacherScheduleDetails.TeacherScheduleId
                );
                if (teacherSchedule != null && teacherSchedule.Capacity == 1)
                {
                    await _context.Database.ExecuteSqlRawAsync(
                        "UPDATE teacher_schedules_details SET Status = {0}, Reason = {1} WHERE Id = {2}",
                        detail.Status,
                        detail.Reason ?? "",
                        detail.TeacherScheduleDetailsId
                    );
                }
            }

            return new StudentScheduleDetailsDto();
        }

        /// <summary>
        /// 更新学生课表状态
        /// </summary>
        public async Task<StudentScheduleDetailsDto> UpdateStatusAsync(
            Guid id,
            ScheduleStatus status,
            string reason = null
        )
        {
            var detail = await _studentScheduleDetailsRepository.GetByIdAsync(id);
            if (detail == null)
            {
                throw new ArgumentException("学生课表详情不存在", nameof(id));
            }

            detail.Status = status;
            detail.Reason = reason;

            await _studentScheduleDetailsRepository.UpdateAsync(detail);

            return new StudentScheduleDetailsDto();
        }

        /// <summary>
        /// 删除学生课表详情
        /// </summary>
        public async Task DeleteAsync(Guid id)
        {
            using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                // 使用AsNoTracking获取学生课表详情，避免实体跟踪
                var detail = await _context
                    .StudentScheduleDetails.AsNoTracking()
                    .FirstOrDefaultAsync(x => x.Id == id);

                if (detail == null)
                {
                    throw new ArgumentException("学生课表详情不存在", nameof(id));
                }
                // 先获取订单详情ID，因为删除后无法访问
                var orderDetailId = detail.OrderDetailId;

                // 直接使用EF Core删除学生课表详情，避免通过仓储层
                await _context.Database.ExecuteSqlRawAsync(
                    "UPDATE student_schedules_details SET IsDeleted = 1 WHERE Id = {0}",
                    id
                );

                // 检查是否存在其他记录
                var count = await _context
                    .StudentScheduleDetails.AsNoTracking()
                    .Where(x => x.OrderDetailId == orderDetailId)
                    .CountAsync();

                if (count == 0)
                {
                    // 直接使用EF Core删除订单详情，避免通过仓储层
                    await _context.Database.ExecuteSqlRawAsync(
                        "UPDATE order_details SET IsDeleted = 1 WHERE Id = {0}",
                        orderDetailId
                    );
                }

                // 提交事务
                await transaction.CommitAsync();
            }
            catch (Exception ex)
            {
                // 回滚事务
                await transaction.RollbackAsync();
                _logger.LogError(ex, "删除学生课表详情时发生错误: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 批量删除学生课表详情
        /// </summary>
        public async Task DeleteRangeAsync(List<Guid> ids)
        {
            if (ids == null || !ids.Any())
                return;

            using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                // 使用AsNoTracking获取学生课表详情，避免实体跟踪
                var details = await _context
                    .StudentScheduleDetails.AsNoTracking()
                    .Where(x => ids.Contains(x.Id))
                    .ToListAsync();

                if (!details.Any())
                    return;

                // 获取所有相关的订单详情ID
                var orderDetailIds = details.Select(x => x.OrderDetailId).Distinct().ToList();

                // 直接使用SQL批量删除学生课表详情

                await _context.Database.ExecuteSqlRawAsync(
                    "UPDATE student_schedules_details SET IsDeleted = 1 WHERE Id IN ({0})",
                    string.Join(",", ids)
                );

                // foreach (var id in ids)
                // {
                //     await _context.Database.ExecuteSqlRawAsync(
                //         "DELETE FROM StudentScheduleDetails WHERE Id = {0}", id);
                // }

                // 检查每个订单详情是否还有关联的学生课表
                foreach (var orderDetailId in orderDetailIds)
                {
                    var count = await _context
                        .StudentScheduleDetails.AsNoTracking()
                        .Where(x => x.OrderDetailId == orderDetailId)
                        .CountAsync();

                    if (count == 0)
                    {
                        // 直接使用SQL删除订单详情
                        await _context.Database.ExecuteSqlRawAsync(
                            "UPDATE order_details SET IsDeleted = 1 WHERE Id = {0}",
                            orderDetailId
                        );
                    }
                }

                await transaction.CommitAsync();
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                _logger.LogError(ex, "批量删除学生课表详情时发生错误: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 检查时间冲突
        /// </summary>
        public async Task<bool> HasTimeConflictAsync(
            Guid orderDetailId,
            DateTime startTime,
            DateTime endTime,
            Guid? excludeId = null
        )
        {
            return await _studentScheduleDetailsRepository.HasTimeConflictAsync(
                orderDetailId,
                startTime,
                endTime,
                excludeId
            );
        }

        /// <summary>
        /// 分页查询学生课表详情
        /// </summary>
        public async Task<PagedResult<StudentScheduleDetailsDto>> GetPagedAsync(
            StudentScheduleDetailsPageRequest request
        )
        {
            // 1. 调用仓储层的分页查询方法
            var result = await _studentScheduleDetailsRepository.GetPagedAsync(request);

            var _dtoItems = new List<StudentScheduleDetailsDto>(result.Items.Count);
            foreach (var item in result.Items)
            {
                var dto = _mapper.Map<StudentScheduleDetailsDto>(item);
                _dtoItems.Add(dto);
            }
            // 3. 转换结果为DTO
            return new PagedResult<StudentScheduleDetailsDto>
            {
                Items = _dtoItems,
                Total = result.Total,
            };
        }

        /// <summary>
        /// 获取教师课表集合
        /// </summary>
        public async Task<List<TeacherScheduleListDto>> GetTeacherScheduleListAsync(
            TeacherScheduleListRequest request
        )
        {
            var dtos = new List<TeacherScheduleListDto>();

            var schedules = await _context
                .StudentScheduleDetails.Include(ss => ss.TeacherScheduleDetails)
                .Include(ss => ss.OrderDetail.Student)
                .Include(ss => ss.TeacherScheduleDetails.TeacherSchedule)
                .Include(ss => ss.TeacherScheduleDetails.TeacherSchedule.Course)
                .Include(ss => ss.TeacherScheduleDetails.TeacherSchedule.Classroom)
                .Where(ss =>
                    ss.TeacherScheduleDetails.TeacherSchedule.TeacherId == request.TeacherId
                    && ss.TeacherScheduleDetails.StartTime >= request.StartDate
                    && ss.TeacherScheduleDetails.EndTime <= request.EndDate
                    && ss.TeacherScheduleDetails.TeacherSchedule != null
                    && !ss.TeacherScheduleDetails.TeacherSchedule.IsDeleted
                    && !ss.OrderDetail.IsDeleted
                    && !ss.TeacherScheduleDetails.IsDeleted
                    && ss.Status == ScheduleStatus.Normal
                    && ss.TeacherScheduleDetails.Status == ScheduleStatus.Normal
                )
                .ToListAsync();

            //根据schedules，统计相同TeacherScheduleDetailsId的课表和学生列表
            var teacherScheduleDetailsList = schedules
                .GroupBy(x => x.TeacherScheduleDetailsId)
                .Select(x => new
                {
                    id = x.Key,
                    startTime = x.First().TeacherScheduleDetails.StartTime,
                    endTime = x.First().TeacherScheduleDetails.EndTime,
                    Course = x.First().TeacherScheduleDetails.TeacherSchedule.Course,
                    Classroom = x.First().TeacherScheduleDetails.TeacherSchedule.Classroom,
                    Students = x.Select(y => y.OrderDetail?.Student).ToList(),
                    StudentScheduleDetails = x.ToList(), // 直接使用当前分组的学生课表详情列表
                    Status = x.First().TeacherScheduleDetails.Status,
                    Reason = x.First().TeacherScheduleDetails.Reason,
                    Remarks = x.First().TeacherScheduleDetails.Remarks,
                    CourseType = x.First().TeacherScheduleDetails.CourseType,
                })
                .ToList();

            foreach (var schedule in teacherScheduleDetailsList)
            {
                dtos.Add(
                    new TeacherScheduleListDto
                    {
                        StartTime = schedule.startTime,
                        EndTime = schedule.endTime,
                        Status = schedule.Status,
                        Reason = schedule.Reason,
                        Remarks = schedule.Remarks,
                        Course = _mapper.Map<CourseDto>(schedule.Course),
                        Classroom = _mapper.Map<ClassroomDto>(schedule.Classroom),
                        CourseType = schedule.CourseType,
                        Students = schedule
                            .Students.Select(x => _mapper.Map<StudentDto>(x))
                            .ToList(),
                        StudentScheduleDetails = schedule
                            .StudentScheduleDetails.Select(x => new StudentScheduleDetailsDto
                            {
                                Id = x.Id,
                                OrderDetailId = x.OrderDetailId,
                                TeacherScheduleDetailsId = x.TeacherScheduleDetailsId,
                                Status = x.Status,
                                Reason = x.Reason,
                                Remarks = x.Remarks,
                                CourseType = x.CourseType,
                                IsForceCheck = x.IsForceCheck,
                                Student = _mapper.Map<StudentDto>(x.OrderDetail?.Student),
                            })
                            .ToList(),
                    }
                );
            }
            return dtos;
        }
    }
}
